package com.wuwei.elearning.question.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wuwei.elearning.exception.ElearningMysqlException;
import com.wuwei.elearning.question.domain.*;
import com.wuwei.elearning.question.mapper.*;
import com.wuwei.elearning.question.service.GradeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wuwei.elearning.setting.domain.User;
import com.wuwei.elearning.setting.mapper.UserMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 班级表,一个班级有很多学员和一个班主任 服务实现类
 * </p>
 *
 * @author wuwei
 * @since 2024-08-12
 */
@Service
@Transactional
public class GradeServiceImpl extends ServiceImpl<GradeMapper, Grade> implements GradeService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private GradeMapper gradeMapper;

    /**
     * 添加一个班级
     * @param gradeName 班级名称
     * @param students 班级学生的清单，user表中status为2的用户id集合
     * @param account 创建班级的人的账号
     * @param type 班级类型，0为基础执照班，1为机型班，现在先只设这两个
     * @param teacher 班主任的，user表中status为1的用户id
     */
    @Override
    public void add(String gradeName, List<Long> students, Long account, Integer type, Long teacher) {
        Grade grade = new Grade();

        //grade的name要求唯一
        ifGradeNameNotOnly(gradeName);

        User user = userMapper.selectById(teacher);

        grade.setType(type);
        grade.setCreatedBy(account);
        grade.setCreatedTime(LocalDateTime.now());
        grade.setName(gradeName);
        if (teacher != null) {
            grade.setTeacherId(teacher);
        }
        if (user != null) {
            grade.setTeacherName(user.getName());
        }
        gradeMapper.insert(grade);

        if (students.size()>0) {
            List<User> users = userMapper.selectBatchIds(students);
            users.forEach(u->{
                u.setGradeId(grade.getId());
                userMapper.updateById(u);
            });
        }

    }

    /**
     * 更新一个班级
     * @param id grade表的主键
     * @param gradeName 班级名称
     * @param students 班级学生的清单，user表中status为2的用户id集合
     * @param account 创建班级的人的账号
     * @param type 班级类型，0为基础执照班，1为机型班，现在先只设这两个
     * @param teacher 班主任的，user表中status为1的用户id
     */
    @Override
    public void myUpdate(Long id, String gradeName, List<Long> students, Long account, Integer type, Long teacher) {
        //gradeName不能与别的grade重复，即如果修改了班级名，那么这个班级名不能是已存在的班级名
        //1.先查询班级名是否修改
        Grade select = gradeMapper.selectById(id);
        if (!select.getName().equals(gradeName)) {//如果班级名被修改
            //2.如果班级名已经修改，再查询班级名是否重复
            //grade的name要求唯一
            ifGradeNameNotOnly(gradeName);
        }

        Grade grade = new Grade();

        User user = userMapper.selectById(teacher);

        grade.setType(type);
        grade.setUpdatedBy(account);
        grade.setUpdatedTime(LocalDateTime.now());
        grade.setName(gradeName);
        grade.setId(id);
        if (teacher != null) {
            grade.setTeacherId(teacher);
        }
        if (user != null) {
            grade.setTeacherName(user.getName());
        }
        gradeMapper.updateById(grade);

        //这里修改学员信息，先把user表中对应grade_id的用户表查出来，删除其表中所有的grade，再重新更新gradeId
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getGradeId,id);
        List<User> selectList = userMapper.selectList(queryWrapper);
        if (selectList.size()>0) {
            userMapper.batchSetGradeIdNull(selectList);
        }

        //重新更新gradeId
        if (students.size()>0) {
//            List<User> users = userMapper.selectBatchIds(students);
//            users.forEach(u->{
//                u.setGradeId(grade.getId());
//                userMapper.updateById(u);
//            });
            userMapper.batchUpdateGradeId(students,grade.getId());
        }
    }

    @Resource
    private QuestionItemMapper questionItemMapper;

    @Resource
    private QuestionItemRaletionQuestionMapper questionItemRaletionQuestionMapper;

    @Resource
    private TestResultMapper testResultMapper;

    @Resource
    private TestAnswersMapper testAnswersMapper;

    /**
     * 删除班级信息的方法
     * 1.删除班级信息grade表
     * 2.删除和班级关联的试卷questionItem表
     * 3.删除和questionItem关联的question_item_raletion_question
     * 4.删除和questionItem表的id关联的test_result表
     * 5.删除和questionItem表的id关联的test_answers表
     * 6.接触学员与班级的联系
     * @param id grade表的主键
     */
    @Override
    @Transactional
    public void myRemove(Long id) {
        gradeMapper.deleteById(id);
        LambdaQueryWrapper<QuestionItem> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(QuestionItem::getGradeId,id);
        List<QuestionItem> questionItems = questionItemMapper.selectList(queryWrapper1);
        List<Long> questionItemIds = questionItems.stream().map(QuestionItem::getId).collect(Collectors.toList());

        if (questionItemIds.size()>0) {
            LambdaQueryWrapper<QuestionItemRaletionQuestion> queryWrapper2 = new LambdaQueryWrapper<>();
            queryWrapper2.in(QuestionItemRaletionQuestion::getQuestionItemId,questionItemIds);
            questionItemRaletionQuestionMapper.delete(queryWrapper2);

            LambdaQueryWrapper<TestResult> queryWrapper3 = new LambdaQueryWrapper<>();
            queryWrapper3.in(TestResult::getQuestionItemId,questionItemIds);
            testResultMapper.delete(queryWrapper3);

            LambdaQueryWrapper<TestAnswers> queryWrapper4 = new LambdaQueryWrapper<>();
            queryWrapper4.in(TestAnswers::getQuestionItemId,questionItemIds);
            testAnswersMapper.delete(queryWrapper4);
        }

        questionItemMapper.delete(queryWrapper1);

        LambdaQueryWrapper<User> queryWrapper5 = new LambdaQueryWrapper<>();
        queryWrapper5.eq(User::getGradeId,id);
        List<User> users = userMapper.selectList(queryWrapper5);
        if (users.size()>0) {
            userMapper.batchSetGradeIdNull(users);
        }
    }

    /**
     * 统计学员各科的平均分
     * @param subjectId
     * @param gradeId
     * @return
     */
    @Override
    public Map<String, Object> getStatictics(Long subjectId, Long gradeId) {
        /*
    1.获取该班级的所有学员
    2.查询每名学员各科的平均分
    3.如果subjectId等于5或者6，代表是M5或者M6，则只查询M5或者M6的学员
    4.查出来的学员还要过滤一次，如果学员的subject不为空，那么要去看他的subject，如果出来的subjectId不在他的范围内就要把它去掉
     */
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getGradeId,gradeId);
        //3.如果subjectId等于5或者6，代表是M5或者M6，则只查询M5或者M6的学员
        //如果是补差学员，要考虑有些课程是他不上的
        if (subjectId == 5||subjectId == 6) {
            if (subjectId == 5) {
                queryWrapper.and(q->q.eq(User::getLicense,"TA").or(a->a.eq(User::getLicense,"补差")));
            } else {
                queryWrapper.and(q->q.eq(User::getLicense,"PA").or(a->a.eq(User::getLicense,"补差")));
            }
        }

        List<User> selectUser = userMapper.selectList(queryWrapper);
        List<User> users = new ArrayList<>();

        for (User user : selectUser) {
            String subject = user.getSubject();
            List<Long> subjectIds = JSON.parseArray(subject, Long.class);
            //非补差的学员subject为空
            if (subject==null&&!("补差").equals(user.getLicense())) {
                users.add(user);
                //补差的学员设置了subject属性，而且license为补差
            } else if(subject!=null&&user.getLicense().equals("补差")) {
                if (subjectIds.contains(subjectId)) {
                    users.add(user);
                }
            } else {
                throw new ElearningMysqlException(30045,"user表的subject为空时，license不能为补差，user表的subject不为空时，license必须为补差！");
            }
        }

        Map<String,Object> map = new HashMap<>();
        if (users.size()==0) {
            throw new ElearningMysqlException(30044,"该班级还未设置学员信息！");
        }
        //查询对应科目的试卷
        LambdaQueryWrapper<QuestionItem> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(QuestionItem::getGradeId,gradeId).eq(QuestionItem::getSubjectId,subjectId);
        List<QuestionItem> questionItems = questionItemMapper.selectList(queryWrapper1);
        List<String> names = new ArrayList<>();
        List<Long> accounts = new ArrayList<>();
        List<Double> scores = new ArrayList<>();
        if (questionItems.size()==0) {
            //此时所有学员分数都是0
            for (User user : users) {
                String name = user.getName();
                names.add(name);
                scores.add(0D);
            }
        }
        else {
            List<Long> questionItemIds = questionItems.stream().map(QuestionItem::getId).collect(Collectors.toList());
            //查询该科目各学员的平均分
            for (User user : users) {
                Long account = user.getAccount();
                String name = user.getName();
                LambdaQueryWrapper<TestResult> queryWrapper2 = new LambdaQueryWrapper<>();
                queryWrapper2.eq(TestResult::getAccount,account).in(TestResult::getQuestionItemId,questionItemIds);
                Integer sum = testResultMapper.myAllScores(questionItemIds, account);
                sum = sum==null?0:sum;
                scores.add((double) (sum/questionItems.size()));
                names.add(name);
                accounts.add(user.getAccount());
            }
        }
        map.put("names",names);
        map.put("scores",scores);
        map.put("accounts",accounts);
        return map;
    }

    @Override
    public int getUserRank(User user) {
        Long gradeId = user.getGradeId();
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getStatus,2).eq(User::getGradeId,gradeId);
        //1.查询该学生所在班级的所有其他学员
        List<User> users = userMapper.selectList(queryWrapper);
        //查询所有学员的平均分
        //逐个查询每个学员
        Map<Long,Double> map = new HashMap<>();
        for (User everyUser : users) {
            String license = everyUser.getLicense();
            //如果该名学员所学的执照是PA，则只查询M1 M2 M3 M6的试卷
            //如果是TA，则只查询M1 M2 M3 M5
            //如果是补差，则根据其subject属性来查询
            LambdaQueryWrapper<QuestionItem> queryWrapper1 = new LambdaQueryWrapper<>();
            switch (license) {
                case "TA":
                    //TA学员不上M6
                    queryWrapper1.eq(QuestionItem::getGradeId,gradeId).ne(QuestionItem::getSubjectId,6);
                    break;
                case "PA":
                    //PA学员不上M5
                    queryWrapper1.eq(QuestionItem::getGradeId,gradeId).ne(QuestionItem::getSubjectId,5);
                    break;
                case "补差":
                    String subject = everyUser.getSubject();
                    if (subject==null) {
                        throw new ElearningMysqlException(30035,"学员为补差时，必须设置subject信息！");
                    } else {
                        List<Long> subjectIds = JSON.parseArray(subject, Long.class);
                        if (subjectIds.size()==0) {
                            throw new ElearningMysqlException(30035,"user表的subject属性不合法!");
                        }
                        queryWrapper1.eq(QuestionItem::getGradeId,gradeId).in(QuestionItem::getSubjectId,subjectIds);
                    }
                    break;
                case "":
                    throw new ElearningMysqlException(30035,"请尽快设置学员所学执照类型！");
                default:
                    throw new ElearningMysqlException(30035,"user表的license只能为TA、PA、或补差！");
            }
            List<QuestionItem> questionItems = questionItemMapper.selectList(queryWrapper1);
            List<Long> questionIds = questionItems.stream().map(QuestionItem::getId).collect(Collectors.toList());
            Long account = everyUser.getAccount();
            if (questionItems.size()==0) {
                map.put(account,0D);
            } else {
                Integer allScore = testResultMapper.myAllScores(questionIds,account);
                allScore = allScore==null?0:allScore;
                Double average = (double) (allScore / questionItems.size());
                map.put(account,average);
            }
        }

        Long userAccount = user.getAccount();
        return getRank(userAccount, map);
    }

    /**
     * 查找某学员的某科成绩分数变化情况
     * @param subjectId
     * @param gradeId
     * @param account
     * @return
     */
    @Override
    public Map<String, Object> showDetail(Long subjectId, Long gradeId, Long account) {
        /**
         * 1.获取该班级该科目所有试卷
         * 2.获取该学生对应试卷的所有分数
         */
        LambdaQueryWrapper<QuestionItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(QuestionItem::getSubjectId,subjectId).eq(QuestionItem::getGradeId,gradeId).orderByAsc(QuestionItem::getId);
        List<QuestionItem> questionItems = questionItemMapper.selectList(queryWrapper);
        //1.获取该班级该科目所有试卷
        List<Long> questionItemsIds = questionItems.stream().map(QuestionItem::getId).collect(Collectors.toList());

        //2.获取该学生对应试卷的所有分数
        LambdaQueryWrapper<TestResult> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.eq(TestResult::getAccount,account).in(TestResult::getQuestionItemId,questionItemsIds).orderByAsc(TestResult::getQuestionItemId);
        List<TestResult> testResults = testResultMapper.selectList(queryWrapper2);

        //设置日期格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        //构造返回数据
        List<String> dateTimes = questionItems.stream().map(t -> {
            LocalDateTime createTime = t.getCreateTime();
            return createTime.format(formatter);
        }).collect(Collectors.toList());

        List<Integer> results = new ArrayList<>();
        int sub = 0;

        for (int i = 0; i < testResults.size(); i++) {
            TestResult testResult = testResults.get(i);
            Long questionItemId = testResult.getQuestionItemId();
            Long question_Item_Id = questionItemsIds.get(i+sub);
            if (!question_Item_Id.equals(questionItemId)) {
                //如果出过试卷了以前未完成补0
                results.add(0);
                sub++;
            }
            results.add(testResult.getScore());
        }

        //如果刚出的卷有未完成的也补0
        sub = questionItems.size()-results.size();
        for (int i = 0; i < sub; i++) {
            results.add(0);
        }

        Map<String ,Object> map = new HashMap<>();
        map.put("dateTimes",dateTimes);
        map.put("results",results);
        return map;
    }

    /**
     * 根据 key 查找 value 的排名
     * @param targetKey
     * @param scores Map<Long,Float>这样的数据，key表示account，学员账号，value表示学员的平均分
     * @return
     */
    private int getRank(Long targetKey, Map<Long, Double> scores) {

        // 获取对应的 value
        Double targetValue = scores.get(targetKey);
        if (targetValue == null) {
            System.out.println("Key not found.");
            return -1;
        }

        // 获取所有的 value 并进行排序
        List<Double> values = new ArrayList<>(scores.values());
        Collections.sort(values, Collections.reverseOrder()); // 降序排序

        // 计算目标 value 的排名
        int rank = 1; // 排名从 1 开始
        for (Double value : values) {
            if (value.equals(targetValue)) {
                break;
            }
            rank++;
        }

//        System.out.println("The rank of the value for key " + targetKey + " is: " + rank);

        return rank;
    }

    /**
     * 判断grade表的name是否唯一
     * @param gradeName
     */
    private void ifGradeNameNotOnly(String gradeName) {
        LambdaQueryWrapper<Grade> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Grade::getName, gradeName);
        Grade selectOne = gradeMapper.selectOne(queryWrapper);
        if (selectOne != null) {
            throw new ElearningMysqlException(30022, "班级名重复！");
        }
    }

}
